/*
* Copyright (c) Huawei Technologies Co., Ltd. 2022. All rights reserved.
*/

#include "vpc_pipeline/pipeline_define.h"
#include "vpc_pipe_comm.h"
#include "dvpp_cmdlist_log.h"
#include "securec.h"
#include "dvpp_cmdlist_define.h"
#include "dvpp_cmdlist_num_define.h"
#include "vpc_pipe_csc.h"
#include "vpc_pipe_resize.h"

void vpc_pipe_set_channel_cache(const vpc_pipe_ctx_t *ctx, uint32_t run_mode)
{
    CHANNEL_(ctx).cache.sramWrapEn = 0x1; // 默认使能
    CHANNEL_(ctx).cache.runMode = run_mode;
}

void vpc_pipe_reset(const vpc_pipe_ctx_t *ctx)
{
    reset_pipeline(&TOP_(ctx), &CHANNEL_(ctx), &PIPELINE_(ctx));
}

void vpc_pipe_set_ker_fmt(const vpc_pipe_ctx_t *ctx, const vpc_pic_fmt_e kernelFmt)
{
    PIPELINE_(ctx).top.kernelFmt = kernelFmt;
}

void vpc_pipe_set_int_merge(const vpc_pipe_ctx_t *ctx, uint32_t int_merge)
{
    TOP_(ctx).pipeIntMerge = int_merge;
}

void vpc_pipe_set_channel_out_type(const vpc_pipe_ctx_t *ctx, channel_out_type_e type)
{
    PIPELINE_(ctx).top.channelOut = type;
}

void vpc_pipe_set_bitwidth(const vpc_pipe_ctx_t *ctx, bitwidth_e bitwidth)
{
    TOP_(ctx).bitWidth = bitwidth;
}

void vpc_pipe_set_readtype(const vpc_pipe_ctx_t *ctx, read_type_e read_type)
{
    TOP_(ctx).rdChannelSel = read_type;
}

void vpc_pipe_set_errmask(const vpc_pipe_ctx_t *ctx, uint32_t errMask)
{
    TOP_(ctx).errMask |= errMask;
}

void vpc_pipe_set_outpic_size(const vpc_pipe_ctx_t *ctx, uint32_t width, uint16_t height, uint32_t chn)
{
    if (chn == MAIN_CHN) {
        TOP_(ctx).outHeight = height - 1;
        TOP_(ctx).outWidth = width - 1;
    } else if (chn == SUB_CHN_1) {
        TOP_(ctx).out1Height = height - 1;
        TOP_(ctx).out1Width =  width - 1;
    } else if (chn == SUB_CHN_2) {
        TOP_(ctx).out2Height = height - 1;
        TOP_(ctx).out2Width = width - 1;
    }
}

void vpc_pipe_set_top(const vpc_pipe_ctx_t *ctx)
{
    const vpc_pipe_private_data_t *pdata = &ctx->pdata[ctx->vpu_id];
    if (!pdata->src_use_apart_pic) {
        TOP_(ctx).in0Height = SRCROI_(ctx).height - 1;
        TOP_(ctx).in0Width = SRCROI_(ctx).width - 1;
    } else {
        TOP_(ctx).in0Height = pdata->apart_src.height - 1;
        TOP_(ctx).in0Width = pdata->apart_src.width - 1;
    }
    TOP_(ctx).in0Format = vpc_pipe_get_vpc_format(&SRC_FMTCFG_(ctx));

    if (!pdata->dst_use_apart_pic) {
        TOP_(ctx).outHeight = DSTPIC_(ctx, MAIN_CHN).picture_height - 1;
        TOP_(ctx).outWidth = DSTPIC_(ctx, MAIN_CHN).picture_width - 1;
    } else {
        TOP_(ctx).outHeight = pdata->apart_dst[MAIN_CHN].height - 1;
        TOP_(ctx).outWidth = pdata->apart_dst[MAIN_CHN].width - 1;
    }
    TOP_(ctx).outFormat = vpc_pipe_get_vpc_format(&DST_FMTCFG_(ctx, MAIN_CHN));
}

void vpc_pipe_set_top_in1(const vpc_pipe_ctx_t *ctx, const vpc_pipe_pic_info_t *layer1)
{
    vpc_fmt_info_t fmt_info;
    vpc_pipe_init_format_info(&fmt_info, layer1->picture_format);
    TOP_(ctx).in1Height = layer1->picture_height - 1;
    TOP_(ctx).in1Width = layer1->picture_width - 1;
    TOP_(ctx).in1Format = vpc_pipe_get_vpc_format(&fmt_info);
}

void vpc_pipe_set_in0swap(const vpc_pipe_ctx_t *ctx, uint8_t en)
{
    if (!en) {
        PIPELINE_(ctx).input.in0Swap.en = en;
        return;
    }

    PIPELINE_(ctx).input.in0Swap.en = vpc_pipe_get_swap_cfg(&SRC_FMTCFG_(ctx)).en;
    PIPELINE_(ctx).input.in0Swap.inPos = vpc_pipe_get_swap_cfg(&SRC_FMTCFG_(ctx)).inPos;
}

void vpc_pipe_set_outswap(const vpc_pipe_ctx_t *ctx, uint32_t chn, uint8_t en)
{
    if (!en) {
        PIPELINE_(ctx).output[chn].swap.en = en;
        return;
    }

    PIPELINE_(ctx).output[chn].swap.en = vpc_pipe_get_swap_cfg(&DST_FMTCFG_(ctx, chn)).en;
    PIPELINE_(ctx).output[chn].swap.outPos = vpc_pipe_get_swap_cfg(&DST_FMTCFG_(ctx, chn)).outPos;
}

void vpc_pipe_direct_set_outswap(const vpc_pipe_ctx_t *ctx, uint32_t chn, uint32_t pos)
{
    PIPELINE_(ctx).output[chn].swap.en = 1;
    PIPELINE_(ctx).output[chn].swap.outPos = pos;
}

void vpc_pipe_set_in0uvup(const vpc_pipe_ctx_t *ctx, uvup_method_e method)
{
    if (method != UVUP_METHOD_BUTT) {
        PIPELINE_(ctx).input.in0Uvup.en = method;
        return;
    }

    PIPELINE_(ctx).input.in0Uvup.en = vpc_pipe_get_uvup_en(&SRC_FMTCFG_(ctx));
}

void vpc_pipe_set_outuvup(const vpc_pipe_ctx_t *ctx, uint32_t chn, uvup_method_e method)
{
    if (method != UVUP_METHOD_BUTT) {
        PIPELINE_(ctx).output[chn].uvUp.en = method;
        return;
    }

    PIPELINE_(ctx).output[chn].uvUp.en = DUPLICATE;
}

void vpc_pipe_set_in0uvdown(const vpc_pipe_ctx_t *ctx, const uint32_t coeff[6])
{
    uint8_t i;
    if (coeff != NULL) {
        for (i = 0; i < 6; i++) { // 下采样系数有6个
            PIPELINE_(ctx).input.in0UvDown.uv444to422Coeff[i] = coeff[i];
        }

        return;
    }

    for (i = 0; i < 6; i++) { // 下采样系数有6个
        PIPELINE_(ctx).input.in0UvDown.uv444to422Coeff[i] = vpc_pipe_get_uvdown_coeff(&SRC_FMTCFG_(ctx)).val[i];
    }
    PIPELINE_(ctx).input.in0UvDown.uvCross = 1;
}

void vpc_pipe_set_outuvdown(const vpc_pipe_ctx_t *ctx, uint32_t chn, uint8_t en)
{
    const uint32_t coeff_0 = 0;
    const uint32_t coeff_256 = 256;

    PIPELINE_(ctx).output[chn].uvDown.uvCross = 1;
    PIPELINE_(ctx).output[chn].uvDown.uv444to422Coeff[0] = coeff_0;   // 第0个系数
    PIPELINE_(ctx).output[chn].uvDown.uv444to422Coeff[1] = coeff_0;   // 第1个系数
    PIPELINE_(ctx).output[chn].uvDown.uv444to422Coeff[2] = coeff_256; // 第2个系数
    PIPELINE_(ctx).output[chn].uvDown.uv444to422Coeff[3] = coeff_0;   // 第3个系数
    PIPELINE_(ctx).output[chn].uvDown.uv444to422Coeff[4] = coeff_0;   // 第4个系数
    PIPELINE_(ctx).output[chn].uvDown.uv444to422Coeff[5] = coeff_0;   // 第5个系数

    if (!en) {
        PIPELINE_(ctx).output[chn].uvDown.uv422to420FilteEn = 0;
    } else {
        PIPELINE_(ctx).output[chn].uvDown.uv422to420FilteEn = 1;
        PIPELINE_(ctx).output[chn].uvDown.uv422to420ClipEn = 1;
    }
}

void vpc_pipe_set_user_csc(vpc_pipe_ctx_t *ctx, const vpc_pipe_csc_info_t *info)
{
    CSC_INFO_(ctx) = *info;
}

void vpc_pipe_set_in0_csc(const vpc_pipe_ctx_t *ctx)
{
    vpc_pic_fmt_e ker_fmt = PIPELINE_(ctx).top.kernelFmt;
    vpc_pic_fmt_e vpc_fmt = vpc_pipe_get_vpc_format(&SRC_FMTCFG_(ctx));
    color_conv_t *conv = get_color_conv(vpc_fmt, ker_fmt);

    if (ker_fmt == XRGB8888_PACKED && vpc_fmt != XRGB8888_PACKED) {
        PIPELINE_(ctx).input.in0Csc.alphaPaddingEn = 1;
    }

    // 数据转换
    if (!conv) {
        PIPELINE_(ctx).input.in0Csc.cscMode = get_data_cvt_csc_mode(vpc_fmt, ker_fmt);
        PIPELINE_(ctx).input.in0Csc.en = 0;
        return;
    }

    // 色域转换
    PIPELINE_(ctx).input.in0Csc.en = 1;
    get_csc_coeff(conv, PIPELINE_(ctx).input.in0Csc.coeff, &CSC_INFO_(ctx));
    PIPELINE_(ctx).input.in0Csc.cscMode = get_csc_mode(conv, vpc_fmt, ker_fmt);
}

void vpc_pipe_set_out_csc(const vpc_pipe_ctx_t *ctx, uint32_t chn)
{
    vpc_pic_fmt_e ker_fmt = PIPELINE_(ctx).top.kernelFmt;
    vpc_pic_fmt_e vpc_fmt = vpc_pipe_get_vpc_format(&DST_FMTCFG_(ctx, chn));
    color_conv_t *conv = get_color_conv(ker_fmt, vpc_fmt);

    if (ker_fmt != XRGB8888_PACKED && vpc_fmt == XRGB8888_PACKED) {
        PIPELINE_(ctx).output[chn].csc.alphaPaddingEn = 1;
    }

    const vpc_pipe_csc_info_t *info = &CSC_INFO_(ctx);
    // 数据转换
    // 原先himpi场景RGB_FP32_TO_GRAY_FP32是没有开csc的
    if ((!conv) || ((info->csc_matrix != VPC_PIPE_CSC_MATRIX_USER) && (conv->type == RGB_FP32_TO_GRAY_FP32))) {
        PIPELINE_(ctx).output[chn].csc.cscMode = get_data_cvt_csc_mode(ker_fmt, vpc_fmt);
        PIPELINE_(ctx).output[chn].csc.en = 0;
        return;
    }

    // 色域转换
    PIPELINE_(ctx).output[chn].csc.en = 1;
    get_csc_coeff(conv, PIPELINE_(ctx).output[chn].csc.coeff, &CSC_INFO_(ctx));
    PIPELINE_(ctx).output[chn].csc.cscMode = get_csc_mode(conv, ker_fmt, vpc_fmt);
}

void vpc_pipe_set_csc_alpha(const vpc_pipe_ctx_t *ctx, uint32_t alpha)
{
    vpc_pic_fmt_e vpc_fmt = vpc_pipe_get_vpc_format(&DST_FMTCFG_(ctx, MAIN_CHN));
    // 根据输出格式判断是否使能, 只要输出是XRGB格式, 就使能alphaPaddingEn
    if (vpc_fmt == XRGB8888_PACKED) {
        PIPELINE_(ctx).output[MAIN_CHN].csc.alphaPaddingEn = 1;
        PIPELINE_(ctx).output[MAIN_CHN].csc.alpha = alpha;
    }

    return;
}

inline static uint32_t enlarge_min_edge(uint32_t offset)
{
    if (offset <= NUM_2) {
        return 0;
    }
    return ALIGN_DOWN((offset - NUM_2), NUM_2);
}

inline static uint32_t enlarge_max_edge(uint32_t cropLen, uint32_t len, uint32_t offset)
{
    uint32_t max = offset + cropLen - 1;
    if (max + NUM_2 >= len - 1) {
        return (len - 1);
    }
    if (max % NUM_2 == 0) {
        return (max + NUM_3);
    }
    return (max + NUM_2);
}

void vpc_pipe_set_crop_accelerate(vpc_pipe_ctx_t *ctx, const vpc_pipe_crop_para_t *para, uint8_t expend_edge)
{
    if (expend_edge) {
        // 抠图加速时需要上下左右四个边各扩2像素，否则uvup的滤波使能时会造成精度差异
        uint32_t hmin = enlarge_min_edge(para->left_offset);
        uint32_t hmax = enlarge_max_edge(para->crop_width, SRCPIC_(ctx).picture_width, para->left_offset);
        uint32_t vmin = enlarge_min_edge(para->top_offset);
        uint32_t vmax = enlarge_max_edge(para->crop_height, SRCPIC_(ctx).picture_height, para->top_offset);

        uint32_t xstep = vpc_pipe_get_pixel_step(&SRC_FMTCFG_(ctx), X);
        uint32_t ystep = vpc_pipe_get_pixel_step(&SRC_FMTCFG_(ctx), Y);
        // max 存在align后仍为自身的情况，不能简单的使用AlignUp
        SRCROI_(ctx).hmin = ALIGN_DOWN(hmin, xstep);
        SRCROI_(ctx).hmax = ALIGN_DOWN(hmax, xstep) + xstep - 1U;
        SRCROI_(ctx).vmin = ALIGN_DOWN(vmin, ystep);
        SRCROI_(ctx).vmax = ALIGN_DOWN(vmax, ystep) + ystep - 1U;

        SRCROI_(ctx).width = SRCROI_(ctx).hmax - SRCROI_(ctx).hmin + 1U;
        SRCROI_(ctx).height = SRCROI_(ctx).vmax - SRCROI_(ctx).vmin + 1U;
    } else {
        // 直接软件抠图，不做扩边
        SRCROI_(ctx).hmin = para->left_offset;
        SRCROI_(ctx).hmax = para->left_offset + para->crop_width - 1;
        SRCROI_(ctx).vmin = para->top_offset;
        SRCROI_(ctx).vmax = para->top_offset + para->crop_height - 1;
        SRCROI_(ctx).width = SRCROI_(ctx).hmax - SRCROI_(ctx).hmin + 1U;
        SRCROI_(ctx).height = SRCROI_(ctx).vmax - SRCROI_(ctx).vmin + 1U;
    }
}

void vpc_pipe_set_precrop(const vpc_pipe_ctx_t *ctx, const vpc_pipe_crop_para_t *para)
{
    uint32_t crop_hmin = para->left_offset;
    uint32_t crop_vmin = para->top_offset;

    uint32_t hmin = crop_hmin - SRCROI_(ctx).hmin;
    uint32_t hmax = hmin + para->crop_width - 1;
    uint32_t vmin = crop_vmin - SRCROI_(ctx).vmin;
    uint32_t vmax = vmin + para->crop_height - 1;

    if (PIPELINE_(ctx).top.kernelFmt == YUV422_PACKED) {
        hmin = (hmin + 1) / 2;       // YUV422格式约束2对齐
        hmax = ((hmax + 1) / 2) - 1; // YUV422格式约束2对齐
    }

    PIPELINE_(ctx).kernel.preCrop.vmin = vmin;
    PIPELINE_(ctx).kernel.preCrop.vmax = vmax;
    PIPELINE_(ctx).kernel.preCrop.hmin = hmin;
    PIPELINE_(ctx).kernel.preCrop.hmax = hmax;
}

void vpc_pipe_set_resize(const vpc_pipe_ctx_t *ctx, const vpc_pipe_resize_para_t *para, uint32_t chn)
{
    vpc_pipe_resize_mode_e mode = para->interpolation;
    if (para->interpolation == VPC_PIPE_AREA) {
        if ((para->out_height > para->in_height) || (para->out_width > para->in_width)) { // Area缩放算法下放大走BILINEAR
            mode = VPC_PIPE_BILINEAR;
        }
    }

    PIPELINE_(ctx).kernel.resize[chn].funcType = get_func_type(mode); // 默认bilinear
    PIPELINE_(ctx).kernel.resize[chn].alignMode = get_align_mode(mode);
    // TODO NVR场景对标opencv
    PIPELINE_(ctx).kernel.resize[chn].rndCtrl0 = get_rnd_ctrl(mode);

    PIPELINE_(ctx).kernel.resize[chn].incSrc = 0; // 模块内部自动计算步长
    PIPELINE_(ctx).kernel.resize[chn].inHeight = para->in_height;
    PIPELINE_(ctx).kernel.resize[chn].inWidth = para->in_width;
    PIPELINE_(ctx).kernel.resize[chn].outHeight = para->out_height;
    PIPELINE_(ctx).kernel.resize[chn].outWidth = para->out_width;
    PIPELINE_(ctx).kernel.resize[chn].en = resize_en(&PIPELINE_(ctx).kernel.resize[chn]);
}

void vpc_pipe_set_resize_split(const vpc_pipe_ctx_t *ctx, const vpc_pipe_split_para_t *para, uint32_t chn)
{
    PIPELINE_(ctx).kernel.resize[chn].splitEn = 1;
    PIPELINE_(ctx).kernel.resize[chn].en = 1;
    PIPELINE_(ctx).kernel.resize[chn].indexInLeft = para->in.left;
    PIPELINE_(ctx).kernel.resize[chn].indexInRight = para->in.right;
    PIPELINE_(ctx).kernel.resize[chn].indexInTop = para->in.top;
    PIPELINE_(ctx).kernel.resize[chn].indexInBottom = para->in.bottom;

    PIPELINE_(ctx).kernel.resize[chn].indexOutLeft = para->out.left;
    PIPELINE_(ctx).kernel.resize[chn].indexOutRight = para->out.right;
    PIPELINE_(ctx).kernel.resize[chn].indexOutTop = para->out.top;
    PIPELINE_(ctx).kernel.resize[chn].indexOutBottom = para->out.bottom;
}


void vpc_pipe_set_blend(
    const vpc_pipe_ctx_t *ctx, vpc_pipe_blending_type_e type, uint32_t offset, const vpc_pipe_pic_info_t *layer1,
    const vpc_pipe_blend_add_weight_config_t *add_weight_config)
{
    PIPELINE_(ctx).kernel.blend.blendMode = type;
    PIPELINE_(ctx).kernel.blend.lay0InSize = ((SRCPIC_(ctx).picture_width - 1) << 16) | // 高16bit设置宽度
                                              (SRCPIC_(ctx).picture_height - 1);
    PIPELINE_(ctx).kernel.blend.lay1InSize = ((layer1->picture_width - 1) << 16) | // 高16bit设置宽度
                                              (layer1->picture_height - 1);
    PIPELINE_(ctx).kernel.blend.leftPosition = offset;
    // TODO 用户态没有float在用户态转换好进入内核态
    PIPELINE_(ctx).kernel.blend.coefAlpha = add_weight_config->alpha;
    PIPELINE_(ctx).kernel.blend.coefBeta = add_weight_config->beta;
    PIPELINE_(ctx).kernel.blend.coefGamma = add_weight_config->gamma;
    PIPELINE_(ctx).kernel.blend.en = 1;
}

void vpc_pipe_set_xflip(const vpc_pipe_ctx_t *ctx, uint8_t isPre, uint32_t inWidth, uint32_t inHeight)
{
    PIPELINE_(ctx).kernel.flip.enX = 1;
    PIPELINE_(ctx).kernel.flip.isPreX = isPre;
    PIPELINE_(ctx).kernel.flip.inHeight = inHeight - 1;
    PIPELINE_(ctx).kernel.flip.inWidth = inWidth - 1;
}

void vpc_pipe_set_yflip(const vpc_pipe_ctx_t *ctx, uint8_t isPre)
{
    PIPELINE_(ctx).kernel.flip.enY = 1;
    PIPELINE_(ctx).kernel.flip.isPreY = isPre;

    // 使能yflip，frame的起始地址需配置为frame最后一行的起始地址。需要重新配置下输入输出地址
    vpc_pipe_set_in0_cvdr_channel(ctx);
    vpc_pipe_set_out_cvdr_channel(ctx, MAIN_CHN);
}

void vpc_pipe_set_histogram(const vpc_pipe_ctx_t *ctx, uint32_t size, uint64_t addr, uint8_t is_yuvsum)
{
    PIPELINE_(ctx).kernel.histogram.en = 1;
    PIPELINE_(ctx).kernel.histogram.isYuvSum = is_yuvsum;
    PIPELINE_(ctx).kernel.histogram.mode = 0;
    PIPELINE_(ctx).kernel.histogram.readSize = size;
    PIPELINE_(ctx).kernel.histogram.readAddr = addr;
}

void vpc_pipe_set_affine(const vpc_pipe_ctx_t *ctx, affine_t *para, uint8_t en3d)
{
    PIPELINE_(ctx).kernel.affine = *para;
    PIPELINE_(ctx).kernel.affine.en = 1;
    PIPELINE_(ctx).kernel.affine.en3d = en3d;
    CHANNEL_(ctx).cache.en3d = en3d;

    switch (PIPELINE_(ctx).top.kernelFmt) {
        case YUV400:
        case RGB888_PACKED:
        case XRGB8888_PACKED:
        case YUV444_PACKED: {
            PIPELINE_(ctx).kernel.affine.blkWidth = 128; // 只可以配128
            PIPELINE_(ctx).kernel.affine.blkHeight = 128; // 可以配128和256
            break;
        }
        case RGB888_PACKED_FP32: {
            PIPELINE_(ctx).kernel.affine.blkWidth = 32; // 只可以配32
            PIPELINE_(ctx).kernel.affine.blkHeight = 32; // 可以配32和64
            break;
        }
        case YUV400_FP32: {
            PIPELINE_(ctx).kernel.affine.blkWidth = 32; // 只可以配32
            PIPELINE_(ctx).kernel.affine.blkHeight = 32; // 可以配32\64\128\256
            break;
        }
        default: {
            PIPELINE_(ctx).kernel.affine.blkWidth = 32;  // 默认配32
            PIPELINE_(ctx).kernel.affine.blkHeight = 32; // 默认配32
            break;
        }
    }
}

void vpc_pipe_set_filter(const vpc_pipe_ctx_t *ctx, filter_t *para)
{
    // 注意：resize和filter互斥
    PIPELINE_(ctx).kernel.filter = *para;
    PIPELINE_(ctx).kernel.filter.en = 1;
}

void vpc_pipe_set_lut(const vpc_pipe_ctx_t *ctx, vpc_pipe_lut_remap_t *para, uint32_t in_width, uint32_t in_height)
{
    uint32_t i = 0;
    PIPELINE_(ctx).kernel.lut.en = 1;
    PIPELINE_(ctx).kernel.lut.width = in_width;
    PIPELINE_(ctx).kernel.lut.height =  in_height;
    for (; i < 256; i++) { // 256个像素值
        PIPELINE_(ctx).kernel.lut.mapValueYorR[i] = para->map_value_y_or_r[i];
        PIPELINE_(ctx).kernel.lut.mapValueUorG[i] = para->map_value_u_or_g[i];
        PIPELINE_(ctx).kernel.lut.mapValueVorB[i] = para->map_value_v_or_b[i];
    }
}